#ifndef __WED_SLAB_H__
#define __WED_SLAB_H__
#include <stdio.h>
#include <stdint.h>
#include "Wed_framework_config.h"
#include "Wed_common.h"
#include "Wed_errno.h"
#include "kernel/Wed_mutex.h"
#include "print/wed_print.h"

/* \brief zone 魔法数 */
#define WED_SLAB_MAGIC                     0x51ab51ab

/* \brief slab 页信息 */
#define WED_SLAB_PAGE_SIZE                 4096                     /* 页大小 */
#define WED_SLAB_PAGE_MASK                (WED_SLAB_PAGE_SIZE - 1)  /* 页大小掩码 */
#define WED_SLAB_PAGE_BITS                 12                       /* 内存大小与页大小关系 */

/* \brief slab zone 信息 */
#define WED_SLAB_ZONE_LIMIT               (16 * 1024)     /* max slab-managed alloc */
#define WED_SLAB_MIN_ZONE_SIZE            (32 * 1024)     /* zone 最小大小 */
#define WED_SLAB_MAX_ZONE_SIZE            (128 * 1024)    /* zone 最大大小 */
#define WED_SLAB_MAX_N_ZONES               72             /* zone 最大数量 */
#define WED_SLAB_ZONE_RELEASE_THRESH       2              /* threshold number of zones */

#define WED_SLAB_PAGE_TYPE_FREE            0x00
#define WED_SLAB_PAGE_TYPE_SMALL           0x01           /* 小内存，按 zone 分配 */
#define WED_SLAB_PAGE_TYPE_LARGE           0x02           /* 大内存，按页分配 */

#define WED_SLAB_MIN_CHUNK_SIZE            8              /* 分配的内存最小大小 */
#define WED_SLAB_MIN_CHUNK_MASK           (WED_SLAB_MIN_CHUNK_SIZE - 1)

/* \brief slab 页信息结构体 */
struct Wed_slab_page_hdr {
    struct Wed_slab_page_hdr *p_next;      /* 下一个有效的页 */
    unsigned long             page;        /* 页数量  */
    /* 占位数据（页大小减去前面两个成员的大小） */
    char                      dummy[WED_SLAB_PAGE_SIZE - (sizeof(struct wed_slab_page_hdr *) + sizeof(unsigned long))];
};

/* \brief slab 内存块信息结构体 */
struct Wed_slab_chunk {
    struct Wed_slab_chunk *p_c_next;
};

/* \brief slab zone 信息结构体 */
struct Wed_slab_zone {
    int32_t                z_magic;        /* 魔法数 */
    int32_t                z_nfree;        /* 空闲内存块的数量 */
    int32_t                z_nmax;         /* 内存块总数 */

    struct Wed_slab_zone  *p_z_next;       /* zoneary[] link if z_nfree non-zero */
    uint8_t               *p_z_baseptr;    /* 内存起始地址 */

    int32_t                z_uindex;       /* 当前分配的内存块索引 */
    int32_t                z_chunksize;    /* 每个内存块的大小 */

    int32_t                z_zoneindex;    /* zone 数组索引 */
    struct Wed_slab_chunk *p_z_freechunk;  /* 空闲的内存块链表 */
};

/* \brief slab 页管理器结构体 */
struct Wed_slab_memusage {
    uint32_t type: 2 ;       /* 页类型 */
    uint32_t size: 30;       /* 分配的页数量或当前页在 zone 的页偏移 */
};

/**
 * \brief slab 页分配
 *
 * @param n_pages 要分配的页数量
 *
 * \retval 成功返回分配的页起始地址
 */
void *Wed_slab_page_alloc(unsigned long n_pages);
/**
 * \brief slab 页释放
 *
 * @param p_addr  页起始地址
 * @param n_pages 释放的页数量
 */
void Wed_slab_page_free(void *p_addr, unsigned long n_pages);
/**
 * \brief slab 初始化
 *
 * @param p_begin_addr 内存起始地址
 * @param size         内存大小
 *
 * \retval 成功返回 0
 */
int Wed_slab_init(void *p_begin_addr, unsigned long size);
/**
 * \brief slab 内存分配
 *
 * @param size 要分配的内存大小
 *
 * \retval 成功返回分配的内存起始地址
 */
void *Wed_slab_mem_alloc(unsigned long size);
/**
 * \brief slab 内存释放
 *
 * @param p_mem 要释放的内存地址
 */
void Wed_slab_mem_free(void *p_mem);
#endif
